/*
 * kkUpdateWindow.java
 *
 * Created on January 30, 2007, 10:40 PM
 */
//FIX ME : What if files of kkDatabase folder get deleted accidentally
//TODO : adding stop buttons to scan window and update window
//TODO : sigtool in *nix ?
//TODO : config.kk in *nix ?


package kkWindows;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
import java.util.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;

/**
 *
 * @author  Kowshik
 */
public class kkUpdateWindow extends javax.swing.JDialog {
    
    //The following static objects are updated after reading the configuration file under the main folder of KK.
    
    //stores the regular expressions to split the line read from the web page.
    private static String cvdSplitter;
    private static String dailyCvdSplitter;
    //stores teh URL of teh website from which the updates will be downloaded
    private static String websiteURL;
    //stores the URL from which main.cvd can be downloaded
    private static String mainCVD;
    //stores a list of file names that are produced when main.cvd is extracted
    private static String mainCVDContents[];
    //stores the URL from which daily.cvd can be downloaded
    private static String dailyCVD;
    //stores a list of file names that are produced when daily.cvd is extracted
    private static String dailyCVDContents[];
    //stores the path of the file that contains info about the version of the virus signatures that were downloaded during the last update.
    private static String dbaseVersion;
    //stores the path of sigExtractor utility that extracts contents from CVD files
    private static String sigExtractor;
    //stores the path of virus signatures data base on the hard drive
    private static String sigPath;
    //stores the location of main KillerKitty folder.
    private static String kkLocation;
    
    private static String tempFolder="temp";
    //constants
    private static final int MAINCVD_CONTENTS=1;
    private static final int DAILYCVD_CONTENTS=2;
    
    //static block to initialize the static variables
    static{
        //Sets the location of main KillerKitty folder
        kkLocation=System.getProperty("user.dir");
        //used to read the next line from the configuration file
        String nextLine;
        //used as a temporary array to store the return value of the split function
        String tempArray[];
        //reads the configuration file
        BufferedReader configReader;
        //used to skipo comments in the config file
        boolean flag=false;
        try{
            //Opens a file handle to the configuration file
            configReader=new BufferedReader(new FileReader(kkLocation+"\\config.kk"));
            //skips comments in the configuration file
                        
            do{
                nextLine=configReader.readLine();
                if(nextLine.charAt(0)=='#')
                    continue;
                flag=true;
            }while(!flag);
            
            //Reads the regular expressions for splitting data the web
            tempArray=nextLine.split("=")[1].split(",");
            cvdSplitter=tempArray[0];
            dailyCvdSplitter=tempArray[1];
            
            //Reads the URL from which the updates will be downloaded
            websiteURL=configReader.readLine().split("=")[1];
            //Reads the URL of main.cvd
            mainCVD=configReader.readLine().split("=")[1];
            mainCVDContents=configReader.readLine().split("=")[1].split(",");
            //Reads the URL of daily.cvd
            dailyCVD=configReader.readLine().split("=")[1];
            dailyCVDContents=configReader.readLine().split("=")[1].split(",");
            //Reads the path of the file that contains info about the version of the virus signatures that were downloaded during the last update.
            dbaseVersion=kkLocation+configReader.readLine().split("=")[1];
            //Reads the path of sigExtractor utility that extracts contents from CVD files
            sigExtractor=kkLocation+configReader.readLine().split("=")[1];
            //Reads the path of virus signatures data base on the hard drive
            sigPath=kkLocation+configReader.readLine().split("=")[1];
            
            //Test Lines
            
            System.out.println("\n\nWeb Content Splitter="+cvdSplitter+","+dailyCvdSplitter);
            System.out.println("Website URL="+websiteURL);
            System.out.println("\nURL - main.cvd="+mainCVD);
            System.out.println("\nContents of main.cvd=");
            for(String content : mainCVDContents)
                System.out.print(content+" ");
            System.out.println("\nContents of daily.cvd=");
            for(String content : dailyCVDContents)
                System.out.print(content+" ");
            System.out.println("\nDatabase version="+dbaseVersion);
            System.out.println("\nExtractor Path="+sigExtractor);
            System.out.println("\nVirus Signatures="+sigPath);
            
            
        }
        catch(FileNotFoundException e){
            //CRITICAL ERROR ! config.kk cannot be found !!
            System.out.println("\nCRITICAL ERROR ! - config.kk not found\n"+e);
            System.exit(1);
        }
        catch(IOException e){
            //Catches any IOExceptions and and writes error message to console 
            System.out.println(e);
        }
        
    }
    
    /** Creates new form kkUpdateWindow */
    public kkUpdateWindow(java.awt.Frame parent, boolean modal) {
        super(parent, modal);
        initComponents();
        //updaterInfoTextArea.setBackground(this.getBackground());
    }
    
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
    private void initComponents() {
        updaterTextAreaScrollPane = new javax.swing.JScrollPane();
        updaterInfoTextArea = new javax.swing.JTextArea();
        updateButton = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setTitle("Updater");
        updaterInfoTextArea.setColumns(20);
        updaterInfoTextArea.setEditable(false);
        updaterInfoTextArea.setRows(5);
        updaterInfoTextArea.setBorder(null);
        updaterTextAreaScrollPane.setViewportView(updaterInfoTextArea);

        updateButton.setText("Update");
        updateButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                updateButtonActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addGap(34, 34, 34)
                .addComponent(updaterTextAreaScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 361, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 21, Short.MAX_VALUE)
                .addComponent(updateButton, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(18, 18, 18))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(134, 134, 134)
                        .addComponent(updateButton, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addGroup(layout.createSequentialGroup()
                        .addGap(34, 34, 34)
                        .addComponent(updaterTextAreaScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 270, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap(34, Short.MAX_VALUE))
        );
        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void updateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_updateButtonActionPerformed
        
        //used to get the source of the event
        final JButton button=(JButton)evt.getSource();
        //Disables update button, till the update process gets over
        button.setEnabled(false);
        //Creates a SwingWorker object that is used to update the GUI in the background 
        SwingWorker<Integer,Object> bgUpdater=new SwingWorker(){
            
            //Temporary array of File objects
            File[] tempFiles;
            //used to delete the virus database
            File dbaseDeleter;
            //loop counter
            int i;
            //used to access the machine's internet connection, to dowload the updates
            URL webConn;
            //temporary objects
            String nextLine,tempArray[];
            
            BufferedReader fileReader,lineReader;
            BufferedWriter fileWriter;
            //stores the old((before checking for updates) and new versions(after checking for updates) of the virus signatures
            String oldMainCVDVer,oldDailyCVDVer,newMainCVDVer,newDailyCVDVer;
            int userCommand; // inputs user confirmation before downloading updates
            boolean flagMain,flagDaily; // flags that are used to decide which files to download
            Runtime processSpawner; // spawns sigExtractor process
            public Integer doInBackground(){
                String currDate = (new SimpleDateFormat("MM/dd/yyyy HH:mm:ss")).format(new Date());  // sets currDate to current Date and time
                updaterInfoTextArea.append("\n\n"+currDate+"\n\nChecking for new updates....."); //updates user display
                
                try{
                   webConn = new URL(websiteURL); //attempts a connection to the website
                                      
                   System.out.println(new URL(mainCVD).openConnection().getContentLength()); //prints length of file
                   System.out.println("Checking if file : "+dbaseVersion+" exists"); //prints debug info to console
                   if( ( new File(dbaseVersion) ).exists() ){  // checks if the file storing information about virus data base version  is present
                       System.out.println("File Exists : "+dbaseVersion); // prints debug info to console
                       fileReader = new BufferedReader(new FileReader(dbaseVersion)); // opens a file handle
                       oldMainCVDVer=fileReader.readLine(); // reads current version of primary virus database
                       System.out.println("old main.cvd version : "+oldMainCVDVer);// writes debug info to console
                       oldDailyCVDVer=fileReader.readLine(); // reads the current version of the secondary data base
                       System.out.println("old daily.cvd version : "+oldDailyCVDVer);// writes debug info to console
                       fileReader.close();
                   }
                   
                   /* The following code reads the version number of the virus databse files that are currently available for download
                      The following code is dependent on the website's source code, and thus may be subjected to changes in the future
                   */
                   
                   //reads content from the website
                   lineReader=new BufferedReader(new InputStreamReader(webConn.openStream()));
                   
                   //loops till the line containing the name of the primary database is found
            
                   while ( (nextLine=lineReader.readLine() ).indexOf("main.cvd") ==-1)
                   {
                
                   }
                   //reads the next line
                   //nextLine=nextLine+lineReader.readLine();
                   System.out.println(nextLine);
                   //splits the content read, so that the html tags are removed
                   tempArray = nextLine.split("<*>");
                   //reads the version of the primary data base that is currently available for download
                   newMainCVDVer = tempArray[tempArray.length-1].split("<")[0];
                   
                   //writes debug info to console
                   System.out.println("new main.cvd version = "+newMainCVDVer);            
                   
                   //loops till the line containing the name of the secondary database is found
            
                   while ( (nextLine=lineReader.readLine() ).indexOf("daily.cvd") ==-1)
                   {
                
                   }
                   
                   //reads the next line
                   nextLine=nextLine+lineReader.readLine();            
                   //splits the content read, so that the html tags are removed
                   tempArray = nextLine.split("<*>");            
                   //again splits the content read, so that the <break> tag is removed at the end
                   newDailyCVDVer = tempArray[tempArray.length-1].split("<")[0];
                   //writes debug info to console
                   System.out.println("new daily.cvd version = "+newDailyCVDVer);
                   //closes the handle
                   lineReader.close();
                   //sets the flags to false initially, as the versions of the current databases and the newly available ones are yet to be compared
                   flagMain=flagDaily=false;
                   
                   //Checks if new version number is the same as the current version
                   if(oldMainCVDVer==null || !newMainCVDVer.equals(oldMainCVDVer)){
                     flagMain=true;
                   }
                   if(oldDailyCVDVer==null || !newDailyCVDVer.equals(oldDailyCVDVer)){
                     flagDaily=true;
                   }
                   
                   //by default, sets the user command to "No"
                   userCommand = JOptionPane.NO_OPTION;
                   //writes debug info to console
                   System.out.println(flagMain+" "+flagDaily);
                   //if the updates are available, a message box requesting confirmation from the user is displayed
                   if(flagMain==true || flagDaily==true){
                        updaterInfoTextArea.append("\nUpdates available");
                        userCommand = JOptionPane.showConfirmDialog(button.getParent(),"New Updates are available.\nDo you want to download them ? ","Updates !",JOptionPane.YES_NO_OPTION);                  
                   }
                   //If no updates are available, information is displayed to the user
                   else{
                        currDate = (new SimpleDateFormat("MM/dd/yyyy HH:mm:ss")).format(new Date());
                        updaterInfoTextArea.append("\nNo new updates available"+"\n\n"+currDate);                        
                        JOptionPane.showMessageDialog(button.getParent(),"Your scanner is up-to-date","Info",JOptionPane.INFORMATION_MESSAGE);
                   }
                   
                   //Checks the user command, and downloads updates correspondingly.
                   if(userCommand==JOptionPane.YES_OPTION){
                       
                       //Downloads the primary virus database if it is available for download
                        if(flagMain){
                                 
                                //updates user display                           
                                updaterInfoTextArea.append("\nDownloading Update : main.cvd \n0%");
                                //downloads the primary virus database
                                downloadFile(mainCVD);
                                //updates the user display
                                updaterInfoTextArea.append("\nDownload complete");
                       
                        }
                       //Downloads the secondary virus database if it is available for download
                       
                         if(flagDaily){
                                //updates user display                           
                                updaterInfoTextArea.append("\nDownloading Update : daily.cvd \n0%");
                                //downloads the secondary virus database
                                downloadFile(dailyCVD);
                                //updates user display                           
                                updaterInfoTextArea.append("\nDownload complete");
                       
                         }
                   
                        //Gets the runtime object of the current java application
                        processSpawner=Runtime.getRuntime();
                        //used to wait till sigExtractor extracts the databases
                        Process p;                   
                       
                        //extracts primary database
                        if(flagMain){
                            //Writing to user's display
                            updaterInfoTextArea.append("\nExtracting Primary Virus Database from : \n"+kkLocation+"\\"+"main.cvd"+"  ...");
                            //Spawning sigExtractor to extract primary databse file                                                        
                            p=processSpawner.exec(new String[]{sigExtractor,"-u",kkLocation+"\\"+tempFolder+"\\"+"main.cvd"},null,new File(kkLocation+"\\"+tempFolder));
                            //waits till the primary virus database is extracted
                            p.waitFor();                            
                            //copies the extracted files to sigPath, replacing old database files if necessary
                            copyFiles(MAINCVD_CONTENTS);
                            
                            //deletes compressed primary virus database file that was downloaded into the temporary folder, and teh temporary folder 
                            dbaseDeleter=new File(kkLocation+"\\"+tempFolder);
                            for(File x : dbaseDeleter.listFiles()){
                                if(x.getName().indexOf("main")!=-1)
                                    x.delete();
                            }
                            dbaseDeleter.delete();                           
                            //Updates user info
                            updaterInfoTextArea.append("\nPrimary Virus Signatures extracted successfully ");
                                                        
                        }//end of if
                        
                        //extracts secondary database
                        if(flagDaily){
                            //Writing to user's display'
                             updaterInfoTextArea.append("\nExtracting New Virus Database from : \n"+kkLocation+"\\"+"dailycvd"+"  ...");
                            //Spawning sigExtractor to extract secondary database file                                                        
                            p=processSpawner.exec(new String[]{sigExtractor,"-u",kkLocation+"\\"+tempFolder+"\\"+"daily.cvd"},null,new File(kkLocation+"\\"+tempFolder));
                            //waits till the primary virus database is extracted
                            p.waitFor();
                            
                            //copies the extracted files to sigPath, replacing old database files if necessary
                            copyFiles(DAILYCVD_CONTENTS);
                            
                            //deletes compressed primary virus database file that was downloaded into the temporary folder, and the temporary folder 
                            dbaseDeleter=new File(kkLocation+"\\"+tempFolder);
                            for(File x : dbaseDeleter.listFiles()){
                                if(x.getName().indexOf("daily")!=-1)
                                    x.delete();
                            }
                            dbaseDeleter.delete();                           
                            //Updates user info
                            updaterInfoTextArea.append("\nNew Virus Signatures extracted successfully ");
                        }//end of if
                                               
                        //Updates the file that stores the database version
                        fileWriter=  new BufferedWriter(new FileWriter(dbaseVersion));   
                        fileWriter.write(newMainCVDVer+System.getProperty("line.separator"));
                        fileWriter.write(newDailyCVDVer);
                        fileWriter.close();
                        
                        //updates user display
                        currDate = (new SimpleDateFormat("MM/dd/yyyy HH:mm:ss")).format(new Date());
                        updaterInfoTextArea.append("\nKillerKitty was updated successfully !\n\n"+currDate);
                        //Shows a message box that tells the user that killer kitty was successfully updated
                        JOptionPane.showMessageDialog(button.getParent(),"KillerKitty was updated successfully ! ","Success !",JOptionPane.INFORMATION_MESSAGE);                        
                        
                   }//end of if
                
               
               return 1;
                    
               }
               catch(MalformedURLException e){
                   //catches exception when the URL read from the config file is malformed, and writes error messages to the console
                   System.out.println(e);
                   return -1;
               }
               catch(IOException e){
                   //catches any IOExceptions and writes error messages to the console
                   System.out.println(e);
                   return -1;
               }
               catch(InterruptedException e){
                   System.out.println(e);
                   return -1;
               }
               
                    
           }
                
           public void done(){
               //Enables update button
               button.setEnabled(true);
               
           }
                
        };//end of anonymous class that extends SwingWorker class
        
        //Updates GUI in the background
        bgUpdater.execute();
        
        
    }//GEN-LAST:event_updateButtonActionPerformed
    
   private void downloadFile(String fileURL){
       //sets up a connection to the internet to download files
       URL webConn;
       //writes to the output file
       BufferedOutputStream fileWriter;
       
       BufferedInputStream URLContentReader;
       
       File targetPathCreator;
       
       String nextLine;
       String targetFile=new String();
       int fileLength;
       float downloaded=0.0f;
       System.out.println("here");
       try{
           webConn=new URL(fileURL);
           fileLength=webConn.openConnection().getContentLength();         
           String targetPath=new String();
           if(fileURL.indexOf("main.cvd")!=-1)                
                targetFile="main.cvd";
           
           else if(fileURL.indexOf("daily.cvd")!=-1)               
               targetFile="daily.cvd";
           
           targetPathCreator=new File(kkLocation+"\\"+tempFolder);
           if(! targetPathCreator.exists())
               targetPathCreator.mkdirs();
           else
               System.out.println(targetPathCreator+"exists");
                                 
           targetPath=kkLocation+"\\"+tempFolder+"\\"+targetFile;
           System.out.println("\nTarget Path : "+targetPath+"\nfileLength : "+fileLength);
           fileWriter=new BufferedOutputStream(new FileOutputStream(targetPath));
          
            URLContentReader=new BufferedInputStream(webConn.openStream());
           
           byte[] buffer=new byte[1024];
           int byteCount=0;
           while((byteCount=URLContentReader.read(buffer) ) != -1){
               downloaded+=byteCount;
               updateStatus("\n"+Double.toString(Math.ceil( (downloaded/(float)fileLength) * 100.0f )));
               fileWriter.write(buffer,0,byteCount);
           }
           URLContentReader.close();
           fileWriter.close();
       }
       catch(MalformedURLException e){
           System.out.println(e);
       }
       catch(IOException e){
           System.out.println(e);
       }
   }
   private void copyFiles(int command){
       
       File[] cvdContents;
       int i,j,byteCount=0;
       byte[] buffer=new byte[2048];
       BufferedInputStream fileReader;
       BufferedOutputStream fileWriter;
       
       System.out.println("Copying files ");
       //Deleting files in sigPath
       switch(command){
           case MAINCVD_CONTENTS :
               //Deleting the files present in kkDataBase so that new updates can be copied              
               
               for(File x : new File(sigPath).listFiles()){
                   if(x.getName().indexOf("main")!=-1)
                       x.delete();
               }
               break;
           case DAILYCVD_CONTENTS :
               
               //Deleting the files present in kkDataBase so that new updates can be copied                             
               for(File x : new File(sigPath).listFiles()){
                   if(x.getName().indexOf("daily")!=-1)
                       x.delete();
               }
               
               break;
           default:
               return;               
                              
       }
       
       
       
       try{
           
           cvdContents=new File(kkLocation+"\\"+tempFolder).listFiles();
           for(File x: cvdContents){
               System.out.println(x);
           }
           for(File currFile : cvdContents){
               //Create objects to read and write the contents of the CVD file
               fileReader=new BufferedInputStream(new FileInputStream(currFile));
               fileWriter=new BufferedOutputStream(new FileOutputStream(sigPath+"\\"+currFile.getName()));
               System.out.println(fileReader+"\n"+fileWriter);
               //Copies the file from ths src to destination
               while((byteCount=fileReader.read(buffer)) != -1)                   
                   fileWriter.write(buffer,0,byteCount);
                              
               //Closing the file handles
               fileReader.close();
               fileWriter.close();         
           }
           
           
       }
       catch(IOException e){
           System.out.println(e);
       }
       
       
       
       
   }
   private void updateStatus(final String item){
                      
                String text = updaterInfoTextArea.getText();
                int i;
                for(i=text.length()-1;i>=0;i--){
                    if(text.charAt(i)==' ')
                    break;
                }
       
                updaterInfoTextArea.setText(text.substring(0,i+1)+item+"%");
         }
    
   
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton updateButton;
    private javax.swing.JTextArea updaterInfoTextArea;
    private javax.swing.JScrollPane updaterTextAreaScrollPane;
    // End of variables declaration//GEN-END:variables
    
}
